package com.ruoyi.common.utils.http;

import com.alibaba.fastjson2.JSONObject;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.EntityBuilder;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;

public class HttpPostUtils {
    private static String CONTENTTYPE = "text/html";
    private static String CHARSET = "utf-8";
    private static int timeout = 12000;

    private static MultiThreadedHttpConnectionManager connectionManager = null;

    static {
        connectionManager = new MultiThreadedHttpConnectionManager();
        connectionManager.getParams().setDefaultMaxConnectionsPerHost(5000);
        connectionManager.getParams().setMaxTotalConnections(5000);
        connectionManager.getParams().setSoTimeout(timeout);
        connectionManager.getParams().setConnectionTimeout(timeout);
    }

    /**
     * post json
     * @param url
     * @param data
     * @return
     */
    public static JSONObject postJson(String url, Map<String, Object> data) {
        return postJson(url, data, null);
    }
    /**
     * post json请求带自定义头，支持https
     * @param url
     * @param data
     * @param headers
     * @return
     */
    public static JSONObject postJson(String url, Map<String, Object> data, Map<String, String> headers) {
        JSONObject jsonResult = null;
        CloseableHttpResponse response = null;
        CloseableHttpClient httpClient = null;
        try {
            httpClient = createHttpClient(url);
            HttpPost httpPost = new HttpPost(url);
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(timeout).setConnectTimeout(timeout).build();
            httpPost.setConfig(requestConfig);
            if (headers != null && headers.size() > 0) {
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    httpPost.setHeader(entry.getKey(), entry.getValue());
                }
            }
            String req = "";
            if (null != data) {
                req = JSONObject.toJSONString(data);
                StringEntity entity = new StringEntity(req, "utf-8");
                entity.setContentEncoding("UTF-8");
                entity.setContentType("application/json");
                httpPost.setEntity(entity);
            }
            response = httpClient.execute(httpPost);
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                String result = EntityUtils.toString(response.getEntity(), "utf-8");
                jsonResult = JSONObject.parseObject(result);
                if (jsonResult.get("secret") == null) {
                    //log.info("请求:" + url + "[" + req + "], 返回结果:" + jsonResult);
                }
            } else if (response.getStatusLine().getStatusCode() == HttpStatus.SC_TEMPORARY_REDIRECT) {
                // 307重定向错误
                Header header = response.getFirstHeader("location"); // 跳转的目标地址是在 HTTP-HEAD上
                String realurl = header.getValue(); // 这就是跳转后的地址，再向这个地址发出新申请
               // log.info("重定向请求:" + realurl);
                return postJson(realurl, data);
            } else {
               // log.info("请求:" + url + "[" + req + "], 返回失败:" + response.getStatusLine().getStatusCode());
            }
        } catch (Exception e) {
            //.error("post请求提交异常:" + url, e.getMessage());
        } finally {
            closeHttpClient(response, httpClient);
        }
        return jsonResult;
    }

    public static JSONObject postJSON(String url, Map<String, Object> data) {
        PostMethod httpMethod = null;
        String response = null;
        try {
            HttpClient httpClient = new HttpClient(connectionManager);
            httpMethod = new PostMethod(url);
            RequestEntity requestEntity = new StringRequestEntity(JSONObject.toJSONString(data),
                    "application/json", CHARSET);
            httpMethod.setRequestEntity(requestEntity);
            int state = httpClient.executeMethod(httpMethod);
            if (state == 200) {
                if (httpMethod.getResponseBodyAsStream() != null) {
                    InputStream resStream = httpMethod.getResponseBodyAsStream();
                    BufferedReader br = new BufferedReader( new InputStreamReader(resStream));
                    StringBuffer resBuffer = new StringBuffer();
                    String resTemp = "" ;
                    while ((resTemp = br.readLine()) != null ){
                        resBuffer.append(resTemp);
                    }
                    response = resBuffer.toString();
                    return JSONObject.parseObject(response);
                }
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static JSONObject postJSON(String url, String jsonStr) {
        PostMethod httpMethod = null;
        String response = null;
        try {
            HttpClient httpClient = new HttpClient(connectionManager);
            httpMethod = new PostMethod(url);
            RequestEntity requestEntity = new StringRequestEntity(jsonStr,
                    "application/json", CHARSET);
            httpMethod.setRequestEntity(requestEntity);
            int state = httpClient.executeMethod(httpMethod);
            if (state == 200) {
                if (httpMethod.getResponseBody() != null) {
                    response = new String(httpMethod.getResponseBody(), CHARSET);
                    return JSONObject.parseObject(response);
                }
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static JSONObject get(String url) {
        return execute(url, HttpGet.METHOD_NAME, null, null, null);
    }

    public static JSONObject execute(String url, String methodName, Map<String, Object> data, Map<String, String> headers) {
        return execute(url, methodName, data, null, headers);
    }

    /**
     * http请求支持自定义header和自定义方法
     * @param url
     * @param methodName post/get/put/delete等
     * @param data
     * @param byte_data body文件流
     * @param headers
     * @return
     */
    public static JSONObject execute(String url, String methodName, Map<String, Object> data, byte[] byte_data, Map<String, String> headers) {
        JSONObject jsonResult = null;
        CloseableHttpResponse response = null;
        CloseableHttpClient httpClient = null;
        try {
            httpClient = createHttpClient(url);
            HttpRequestBase request = getRquest(methodName);
            request.setURI(URI.create(url));
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(timeout).setConnectTimeout(timeout).build();
            request.setConfig(requestConfig);
            if (headers != null && headers.size() > 0) {
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    request.setHeader(entry.getKey(), entry.getValue());
                }
            }
            if (null != data) {
                HttpEntity entity = EntityBuilder.create()
                        .setContentEncoding("utf-8")
                        .setContentType(ContentType.APPLICATION_JSON)
                        .setText(JSONObject.toJSONString(data))
                        .build();
                ((HttpEntityEnclosingRequestBase) request).setEntity(entity);
            }
            if (byte_data != null) {
                ((HttpEntityEnclosingRequestBase) request).setEntity(new ByteArrayEntity(byte_data));
            }
            //log.info("请求:[{}]，参数：[{}]", url, data);
            response = httpClient.execute(request);
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                String result = EntityUtils.toString(response.getEntity(), "utf-8");
                jsonResult = JSONObject.parseObject(result);
                //log.info("请求:[{}]，返回结果:[{}]", url, jsonResult);
            } else {
                //log.info("请求返回结果:[{}]", response.getStatusLine().getStatusCode());
            }
        } catch (Exception e) {
            //log.error("请求提交异常:", e.getMessage());
        } finally {
            closeHttpClient(response, httpClient);
        }
        return jsonResult;
    }

    private static HttpRequestBase getRquest(String method) {
        if (HttpGet.METHOD_NAME.equals(method)) {
            return new HttpGet();
        } else if (HttpPost.METHOD_NAME.equals(method)) {
            return new HttpPost();
        } else if (HttpHead.METHOD_NAME.equals(method)) {
            return new HttpHead();
        } else if (HttpOptions.METHOD_NAME.equals(method)) {
            return new HttpOptions();
        } else if (HttpPut.METHOD_NAME.equals(method)) {
            return new HttpPut();
        } else if (HttpPatch.METHOD_NAME.equals(method)) {
            return new HttpPatch();
        } else if (HttpDelete.METHOD_NAME.equals(method)) {
            return new HttpDelete();
        } else if (HttpTrace.METHOD_NAME.equals(method)) {
            return new HttpTrace();
        }
        return new HttpPost();
    }

    public static void closeHttpClient(CloseableHttpResponse response, CloseableHttpClient httpClient) {
        try {
            if (response != null) {
                response.close();
            }
            if (httpClient != null) {
                httpClient.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static CloseableHttpClient createHttpClient(String url) {
        if (url != null && url.indexOf("https") > -1) {
            try {
                SSLContext sslContext = (new SSLContextBuilder()).loadTrustMaterial((KeyStore) null, new TrustStrategy() {
                    public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
                        return true;
                    }
                }).build();
                SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
                return HttpClients.custom().setSSLSocketFactory(sslsf).build();
            } catch (Exception var3) {
                return null;
            }
        }

        return HttpClients.createDefault();
    }

    /**
     * POST请求form-data格式数据
     *
     * @param url
     * @param data
     * @return
     */
    public static JSONObject postFormData(String url, Map<String, String> data) {
        String result = null;
        CloseableHttpClient client = null;
        CloseableHttpResponse response = null;
        try {
            RequestConfig requestConfig = RequestConfig.custom()
                    .setSocketTimeout(timeout)
                    .setConnectTimeout(timeout)
                    .setConnectionRequestTimeout(timeout).build();
            client = HttpClients.custom().setDefaultRequestConfig(requestConfig).build();
            URIBuilder uriBuilder = new URIBuilder(url);

            HttpPost httpPost = new HttpPost(uriBuilder.build());
            httpPost.setHeader("Connection", "Keep-Alive");
            httpPost.setHeader("Charset", CHARSET);
            httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
            Iterator<Map.Entry<String, String>> it = data.entrySet().iterator();
            List<NameValuePair> params = new ArrayList<>();
            while (it.hasNext()) {
                Map.Entry<String, String> entry = it.next();
                NameValuePair pair = new BasicNameValuePair(entry.getKey(), entry.getValue());
                params.add(pair);
            }

            httpPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));

            response = client.execute(httpPost);
            if (response != null) {
                HttpEntity resEntity = response.getEntity();
                if (resEntity != null) {
                    result = EntityUtils.toString(resEntity, CHARSET);
                }
            }
        } catch (ClientProtocolException e) {
            //log.error("post form-data创建连接失败", e.getMessage());
        } catch (IOException e) {
           // log.error("post form-data请求/响应失败", e.getMessage());
        } catch (URISyntaxException e) {
           // log.error("post form-data请求/响应失败", e.getMessage());
        }

        return StringUtils.isBlank(result) ? null : JSONObject.parseObject(result);
    }


    /**
     * 按照“参数=参数值”的模式用“&”字符拼接成字符串
     *
     * @param params
     * @return
     */
    public static String getRequestParams(Map<String, Object> params) {
        List<String> keys = new ArrayList<>(params.keySet());
        Collections.sort(keys);
        StringBuilder paramstr = new StringBuilder();
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = MapUtils.getString(params, key, "");
            if (i == keys.size() - 1) {
                paramstr.append(key).append("=").append(value);
            } else {
                paramstr.append(key).append("=").append(value).append("&");
            }
        }
        return paramstr.toString();
    }

    public static void main(String[] args) {
        Map<String, Object> params = new HashMap<>();
        params.put("voucherCode", "wsawlqwqrewq432019219");
        params.put("orderNo", "2022061000102725952434052782");
        JSONObject orderInfo = HttpPostUtils.postJson("https://gw.youxinsign.com/rxk-saas/api/organ-clue-api/readClues", params);
        //JSONObject orderInfo = HttpPostUtils.postJson("https://beeweb.youxinsign.com:16081/e05-bee-api/e05/api/organ-clue-api/readClues?msa_platform=E05-BEE-ORGAN-WEB", params);

        System.out.println(orderInfo);
    }
}
